// The class is responsible for parsing a job from its XML representation, and build a job instance accordingly.

#include "../include/PocoXMLParser.h"

// Class constructor.
PocoXMLParser::PocoXMLParser(void) {}

// Class destructor. Deletes the effects list it had created.
PocoXMLParser::~PocoXMLParser(void) {
	for (vector<Effect*>::iterator it = effectsList->begin() ; it != effectsList->end(); it++) {
		delete (*it);
	}
	delete effectsList;
}

// Takes the given string and removes all whitespaces from it.
void PocoXMLParser::parseXmlString(std::string& xml){
	//get the factory
	Poco::XML::DOMParser parser;
	//filters white space nodes v1.4.2p
	//parser.setFeature(parser.FEATURE_FILTER_WHITESPACE, true);
	//filter white space nodes v1.3.0 - uni version
	parser.setFeature(Poco::XML::DOMParser::FEATURE_WHITESPACE,false);
	//parse using builder to get fDom representation of the XML string
	fDom = parser.parseString(xml);
}

// Takes the whitespaces-less string, retrieves the job data from it and builds a job instance accordingly.
Job* PocoXMLParser::getParsedXML(){
	Poco::XML::NodeIterator docIterator(Poco::XML::NodeIterator(fDom, Poco::XML::NodeFilter::SHOW_ALL));
	Poco::XML::AutoPtr<Poco::XML::NodeList> childrenList;
	Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> attributeMap;
	Poco::XML::Node* docIteratorNode;
	int input, output, demand, kSize;
	int cvtCounter = 0;
	double sigmaX, sigmaY, scaleFactorX, scaleFactorY;
	effectsList = new vector<Effect*>();
	docIteratorNode = docIterator.nextNode();
	while (docIteratorNode){ // until there are no more xml nodes to read
		attributeMap = docIteratorNode->attributes();
		if (docIteratorNode->nodeName() == "InputRepresentation") { // retrieves the input representation from the xml
			istringstream ( attributeMap->getNamedItem("id")->getNodeValue() ) >> input;
		}
		if (docIteratorNode->nodeName() == "OutputRepresentation") { // retrieves the output representation from the xml
			istringstream ( attributeMap->getNamedItem("id")->getNodeValue() ) >> output;
		}
		else {
			childrenList = docIteratorNode->childNodes(); // accesses a job effect
			if (docIteratorNode->nodeName() == "cvtColor"){
				if (cvtCounter == 0) { // in case there wasn't a cvtColor effect already (since opencv doesn't support grayscaling a photo twice)
					demand = CV_RGB2GRAY;
					CvtColor* cvt = new CvtColor(demand);
					effectsList->push_back(cvt);
					cvtCounter++;
				}
			}
			if (docIteratorNode->nodeName() == "GaussianBlur"){
				istringstream(childrenList->item(0)->firstChild()->getNodeValue()) >> kSize; // retrieves the needed values for GaussianBlur
				istringstream(childrenList->item(1)->firstChild()->getNodeValue()) >> sigmaX;
				istringstream(childrenList->item(2)->firstChild()->getNodeValue()) >> sigmaY;
				demand = enumConverter(childrenList->item(3)->firstChild()->getNodeValue());
				Gaussian* gBlur = new Gaussian(kSize, sigmaX, sigmaY, demand);
				effectsList->push_back(gBlur);
			}
			if (docIteratorNode->nodeName() == "resize") {
				istringstream(childrenList->item(0)->firstChild()->getNodeValue()) >> scaleFactorX; // retrieves the needed values for Resize
				istringstream(childrenList->item(1)->firstChild()->getNodeValue()) >> scaleFactorY;
				demand = enumConverter(childrenList->item(2)->firstChild()->getNodeValue());
				Resize* resize = new Resize(scaleFactorX, scaleFactorY, demand);
				effectsList->push_back(resize);
			}
		}
		docIteratorNode = docIterator.nextNode();
	}
	Job* job = new Job(input, output, *effectsList); // builds a new job from the built effects list.
	return job;
}

// Converts the given enum to int.
int PocoXMLParser::enumConverter(const Poco::XML::XMLString en) {
	int answer;
	if (en == "BORDER_CONSTANT") {
		answer = BORDER_CONSTANT;
	}
	if (en == "BORDER_DEFAULT") {
		answer = BORDER_DEFAULT;
	}
	if (en == "BORDER_ISOLATED") {
		answer = BORDER_ISOLATED;
	}
	if (en == "BORDER_REFLECT") {
		answer = BORDER_REFLECT;
	}
	if (en == "BORDER_REFLECT_101") {
		answer = BORDER_REFLECT_101;
	}
	if (en == "BORDER_REPLICATE") {
		answer = BORDER_REPLICATE;
	}
	if (en == "BORDER_TRANSPARENT") {
		answer = BORDER_TRANSPARENT;
	}
	if (en == "BORDER_WRAP") {
		answer = BORDER_WRAP;
	}
	if (en == "INTER_NEAREST") {
		answer = INTER_NEAREST;
	}
	if (en == "INTER_LINEAR") {
		answer = INTER_LINEAR;
	}
	if (en == "INTER_AREA") {
		answer = INTER_AREA;
	}
	if (en == "INTER_CUBIC") {
		answer = INTER_CUBIC;
	}
	if (en == "INTER_LANCZOS4") {
		answer = INTER_LANCZOS4;
	}
	return answer;
}

